package com.lancoo.edu.platform.operation.commons.utils;


import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.Map;

/**
 * @author cyl
 **/
@Slf4j
public class HttpUtil {

    /**
     * 使用RestTemplate作为Http请求的工具
     */
    private final static RestTemplate REST_TEMPLATE = new RestTemplate();
    private static final int READ_TIMEOUT = 60000;
    private static final int CONNECTION_TIMEOUT = 5000;

    static {
        // SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setConnectTimeout(CONNECTION_TIMEOUT);
        requestFactory.setReadTimeout(READ_TIMEOUT);
        //添加编码，RestTemplate默认编码器是ISO-8859-1,如果接口后台服务对编码进行了控制，会发生中文乱码的情况
        //REST_TEMPLATE.getMessageConverters().set(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        REST_TEMPLATE.setRequestFactory(requestFactory);
    }

    /**
     * get请求
     *
     * @param url 请求地址
     */
    public static String sendGet(String url) {
        return sendGet(url, null, null);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息（query参数）
     * @return 请求结果
     */
    public static String sendGet(String url, Map<String, String> parameterMap) {
        return sendGet(url, null, parameterMap, null);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param headerMap 请求头
     * @param parameterMap 参数信息
     * @return 请求结果
     */
    public static String sendGet(String url, Map<String, String> headerMap, Map<String, String> parameterMap) {
        return sendGet(url, headerMap, parameterMap, null);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息
     * @param body         请求实体（请求体）
     * @return 请求结果
     */
    public static String sendGet(String url, Map<String, String> parameterMap, Object body) {
        return sendGet(url, null, parameterMap, body);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          主接口地址
     * @param parameterMap 请求路径参数
     * @param headerMap    请求头
     */
    public static String sendGet(String url, Map<String, String> headerMap, Map<String, String> parameterMap, Object body) {
        return execute(HttpMethod.GET, url, headerMap, parameterMap, body);
    }


    /**
     * Post请求
     *
     * @param url 请求地址
     */
    public static String sendPost(String url) {
        return sendPost(url, null, null);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息（query参数）
     * @return 请求结果
     */
    public static String sendPost(String url, Map<String, String> parameterMap) {
        return sendPost(url, null, parameterMap, null);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息（query参数）
     * @return 请求结果
     */
    public static String sendPost2(String url, Map<String, String> parameterMap) {
        buildUri(url, parameterMap);
        return sendPost(url, null, parameterMap);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息（query参数）
     * @return 请求结果
     */
    public static String sendPost(String url, Map<String, String> headerMap, Map<String, String> parameterMap) {
        return sendPost2(url, headerMap, parameterMap);
    }

    /**
     * Post请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息
     * @param body         请求实体（请求体）
     * @return 请求结果
     */
    public static String sendPost(String url, Map<String, String> parameterMap, Object body) {
        return sendPost(url, null, parameterMap, body);
    }

    /**
     * Post请求，Map参数
     *
     * @param url          主接口地址
     * @param parameterMap 请求路径参数
     * @param headerMap    请求头
     */
    public static String sendPost(String url, Map<String, String> headerMap, Map<String, String> parameterMap, Object body) {
        return execute(HttpMethod.POST, url, headerMap, parameterMap, body);
    }


    /**
     * Post请求
     *
     * @param url 请求地址
     */
    public static String sendPut(String url) {
        return sendPut(url, null, null);
    }

    /**
     * Get请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息（query参数）
     * @return 请求结果
     */
    public static String sendPut(String url, Map<String, String> parameterMap) {
        return sendPut(url, null, parameterMap, null);
    }

    /**
     * Put 请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息
     * @param body         请求实体（请求体）
     * @return 请求结果
     */
    public static String sendPut(String url, Map<String, String> parameterMap, Object body) {
        return sendPut(url, null, parameterMap, body);
    }

    /**
     * Delete 请求，Map参数
     *
     * @param url          URL地址
     * @param parameterMap 参数信息
     * @param body         请求实体（请求体）
     * @return 请求结果
     */
    public static String sendDelete(String url, Map<String, String> parameterMap, Object body) {
        return sendDelete(url, null, parameterMap, body);
    }

    /**
     * Post请求，Map参数
     *
     * @param url          主接口地址
     * @param parameterMap 请求路径参数
     * @param headerMap    请求头
     */
    public static String sendPost2(String url, Map<String, String> headerMap, Map<String, String> parameterMap) {
        return execute(HttpMethod.POST, url, headerMap, parameterMap);
    }
    /**
     * put 请求，Map参数
     *
     * @param url          主接口地址
     * @param parameterMap 请求路径参数
     * @param headerMap    请求头
     */
    public static String sendPut(String url, Map<String, String> headerMap, Map<String, String> parameterMap, Object body) {
        return execute(HttpMethod.PUT, url, headerMap, parameterMap, body);
    }

    /**
     * DELETE 请求，Map参数
     *
     * @param url          主接口地址
     * @param parameterMap 请求路径参数
     * @param headerMap    请求头
     */
    public static String sendDelete(String url, Map<String, String> headerMap, Map<String, String> parameterMap, Object body) {
        return execute(HttpMethod.DELETE, url, headerMap, parameterMap, body);
    }

    /**
     * Get请求，Map参数  APPLICATION_FORM_URLENCODED
     *
     * @param url          主接口地址
     * @param headerMap    请求头
     * @param parameterMap 请求路径参数
     */
    public static String execute(HttpMethod method, String url, Map<String, String> headerMap, Map<String, String> parameterMap) {
        HttpHeaders headers = new HttpHeaders();
        if (headerMap != null) {
            headerMap.forEach(headers::set);
        }
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        URI uri = buildUri(url, parameterMap);
        HttpEntity<String> stringHttpEntity = new HttpEntity<>(headers);
        String result = "";
        if (log.isDebugEnabled()) {
            log.debug("url:{}", uri);
            log.debug("请求头:{}", JSONObject.toJSONString(headerMap));
            log.debug("参数信息:{}", JSONObject.toJSONString(parameterMap));
        }

        try {
            ResponseEntity<String> exchange = REST_TEMPLATE.exchange(uri, method, stringHttpEntity, String.class);
            if (exchange.getStatusCode().is2xxSuccessful()) {
                result = exchange.getBody();
            } else {
                log.error("url:{}", uri);
                log.error("请求头:{}", JSONObject.toJSONString(headerMap));
                log.error("参数信息:{}", JSONObject.toJSONString(parameterMap));
                log.error("请求失败，响应码：{}", exchange.getStatusCode().value());
                log.error("请求失败，响应结果是：{}", result);
            }
        } catch (Exception exception) {
            log.error("url:{}", uri);
            log.error("请求头:{}", JSONObject.toJSONString(headerMap));
            log.error("查询参数信息:{}", JSONObject.toJSONString(parameterMap));
            log.error("使用RestTemplate请求接口发生异常：", exception);
        }
        return result;
    }

    /**
     * Get请求，Map参数
     *
     * @param url          主接口地址
     * @param headerMap    请求头
     * @param parameterMap 请求路径参数
     */
    public static String execute(HttpMethod method, String url, Map<String, String> headerMap, Map<String, String> parameterMap, Object body) {
        HttpHeaders headers = new HttpHeaders();
        if (headerMap != null) {
            headerMap.forEach(headers::set);
        }
        String requestBody = JSONObject.toJSONString(body);
        //添加请求体，通过json方式传递值
        if (body != null) {
            requestBody = JSONObject.toJSONString(body);
        }
        headers.setContentType(MediaType.APPLICATION_JSON);

        URI uri = buildUri(url, parameterMap);
        HttpEntity<String> stringHttpEntity = new HttpEntity<>(requestBody, headers);
        String result = "";
        if (log.isDebugEnabled()) {
            log.debug("url:{}", uri);
            log.debug("请求头:{}", JSONObject.toJSONString(headerMap));
            log.debug("参数信息:{}", JSONObject.toJSONString(parameterMap));
            log.debug("查询参数信息{}", JSONObject.toJSONString(body));
        }
        try {
            ResponseEntity<String> exchange = REST_TEMPLATE.exchange(uri, method, stringHttpEntity, String.class);
            if (exchange.getStatusCode().is2xxSuccessful()) {
                result = exchange.getBody();
            } else {
                log.error("url:{}", uri);
                log.error("请求头:{}", JSONObject.toJSONString(headerMap));
                log.error("参数信息:{}", JSONObject.toJSONString(parameterMap));
                log.error("查询参数信息{}", JSONObject.toJSONString(body));
                log.error("请求失败，响应码：{}", exchange.getStatusCode().value());
                log.error("请求失败，响应结果是：{}", result);
            }
        } catch (Exception exception) {
            log.error("url:{}", uri);
            log.error("请求头:{}", JSONObject.toJSONString(headerMap));
            log.error("查询参数信息:{}", JSONObject.toJSONString(parameterMap));
            log.error("请求体{}", JSONObject.toJSONString(body));
            log.error("使用RestTemplate请求接口发生异常：", exception);
        }
        return result;
    }

    /**
     * 构建请求地址
     *
     * @param url          URL
     * @param parameterMap 路径参数
     * @return uri
     */
    private static URI buildUri(String url, Map<String, String> parameterMap) {
        UriComponentsBuilder urlComponent = UriComponentsBuilder.fromHttpUrl(url);
        if (parameterMap != null && !parameterMap.isEmpty()) {
            LinkedMultiValueMap<String, String> parameterValueMap = new LinkedMultiValueMap<>();
            parameterMap.forEach(parameterValueMap::add);
            urlComponent.queryParams(parameterValueMap);
        }
        return urlComponent.build().toUri();
    }
}
